import { PokerConfig } from "../config/PokerConfig";
import PokerArray from "./PokerArray";

export class MiniCompose {

    readonly arraies: PokerArray[];
    private sameColor: boolean | undefined;
    private sameType: boolean | undefined;

    get isSameColor() {
        if (this.sameColor === undefined) {
            const colorArray: Set<boolean> = new Set();
            for (const array of this.arraies) {
                if (colorArray.size > 1) break;
                const colorSet = PokerConfig.pokerColor(array.pokers.map(v => v.getPoker()));
                for (const element of colorSet) {
                    colorArray.add(element)
                }
            }
            this.sameColor = colorArray.size === 1;
        }
        return this.sameColor!;
    }

    get isSameType() {
        if (this.sameType === undefined) {
            const typeArray: Set<number> = new Set();
            for (const array of this.arraies) {
                if (typeArray.size > 1) break;
                const typeSet = PokerConfig.pokerType(array.pokers.map(v => v.getPoker()));
                for (const element of typeSet) {
                    typeArray.add(element)
                }
            }
            this.sameType = typeArray.size === 1;
        }
        return this.sameType!;
    }

    constructor(arraies: PokerArray[], sameColor?: boolean, sameType?: boolean) {
        this.arraies = arraies;
        this.sameColor = sameColor;
        this.sameType = sameType;
    }


    toString() {
        return `[${this.arraies.map(v => v.toString()).join('-')}]`
    }
}

export default class PokerCompose {

    readonly sameColorPoker: MiniCompose[] = []; // 红桃/方片 , 黑桃/梅花
    readonly sameTypePoker: MiniCompose[] = []; // 234♥ 567♥ , 567/8910梅花
    readonly spliceChainPoker: MiniCompose[] = []; // 234 567 
    readonly sameChainPoker: MiniCompose[] = []; // 234 234
    readonly pairsChainPoker: MiniCompose[] = []; // 222 333 , 222 333 444
    readonly boomChainPoker: MiniCompose[] = []; // 222 333 , 222 333 444

    constructor(public readonly arraies: PokerArray[]) {
        // 进行分析牌

        // 二链子 +200 x,[567,8910],xxx , x,xxx,[567,8910]  需要检查同花/同色
        // 三链子 +400 x,[234,567,8910] 需要检查同花/同色
        // 若干链子 +800 [A,KQJ,1098,765] 需要检查同花/同色

        // 二对子链 x,[222,333],xxx  x,xxx,[222,333] , A,[AAA,KKK],XXX,J 额外的加分, 不检查同花/同色
        // 三对子链 x,[222,333,444]  额外加分 A,[AAA,KKK,QQQ],J 不检查同花/同色

        // 二杆子链 x,[2222,3333],xxx  x,xxx,[2222,3333] , [AAAA,KKKK],XXX,J 额外加分 不检查同花/同色
        // 三杆子链 x,[2222,3333,4444] , [AAAA,KKKK,QQQQ],J 额外加分 不检查同花/同色

        // 颜色判断 红色 黑色
        const colorArray: PokerArray[][] = [[], []];
        // 类型判断 红桃 , 黑桃 , 方片 , 梅花
        const typeArray: PokerArray[][] = [[], [], [], [], []];

        for (const array of arraies) {
            const pokerEnumArray = array.pokers.map(v => v.getPoker());

            // 链子存在同色
            const colorSet = PokerConfig.pokerColor(pokerEnumArray);
            if (colorSet.size === 1) {
                for (const value of colorSet) {
                    colorArray[value ? 0 : 1].push(array)
                }
            }

            const typeSet = PokerConfig.pokerType(pokerEnumArray);
            if (typeSet.size === 1) {
                for (const value of typeSet) {
                    typeArray[value / PokerConfig.Poker_Type_Base].push(array);
                }
            }
        }

        colorArray.forEach(v => {
            if (v.length > 1) {
                this.sameColorPoker.push(new MiniCompose(v, true, undefined))
            }
        })

        typeArray.forEach(v => {
            if (v.length > 1) {
                this.sameTypePoker.push(new MiniCompose(v, undefined, true))
            }
        })

        //#region 链子 组合判断
        const composeChainArray = arraies.filter(v => {
            return PokerConfig.pokerIsChain(v.pokers.map(a => a.getPoker()))
        });
        if (composeChainArray.length > 1) {
            // 组成一个新的长度的链子 
            const spliceChain = (start: PokerArray, composeArray: PokerArray[]) => {
                const current = [start];
                for (const array of composeArray) {
                    const currentPokerEnums = current.reduce<PokerConfig.EnumPoker[]>((pre, v) => {
                        return pre.concat(v.pokers.map(v => v.getPoker()))
                    }, []).concat(array.pokers.map(v => v.getPoker()))

                    if (PokerConfig.pokerIsChain(currentPokerEnums)) {
                        current.push(array)
                    }
                }
                return current;
            };

            const findSpliceChain = (composeArray: PokerArray[], target: PokerArray[][]) => {
                if (composeArray.length <= 1) {
                    return target;
                }
                const start = composeArray.shift();
                if (!start) {
                    return target;
                };
                const result = spliceChain(start, composeArray);
                if (result.length > 1) {
                    target.push(result);
                    composeArray = composeArray.filter((v) => {
                        return result.indexOf(v) < 0;
                    })
                }

                return findSpliceChain(composeArray, target);
            }

            // 是否存在两条链子 组成的组合链子
            findSpliceChain([...composeChainArray], []).forEach(v => {
                this.spliceChainPoker.push(new MiniCompose(v, undefined, undefined))
            })

            // 是否存在一模一样相同的链子
            const findSameChain = (composeArray: PokerArray[], target: Map<number, PokerArray[]>) => {
                for (const element of composeArray) {
                    const count = element.count();
                    let value = target.get(count);
                    if (!value) {
                        value = [];
                        target.set(count, value);
                    }
                    value.push(element);
                }
                return target;
            }

            findSameChain([...composeChainArray], new Map()).forEach((v, k) => {
                if (v.length > 1) {
                    this.sameChainPoker.push(new MiniCompose(v, undefined, undefined))
                }
            })
        }

        // 对子
        const composePairsArray = arraies.filter(v => {
            return v.length() === 3 && PokerConfig.pokerIsPairs(v.pokers.map(a => a.getPoker()));
        })

        if (composePairsArray.length > 1) {
            // 存在顺序 222 333 444
            // 组成一个新的长度的链子 
            const splicePairs = (start: PokerArray, composeArray: PokerArray[]) => {
                const current = [start];
                for (const array of composeArray) {
                    const currentPokerEnums = current.reduce<PokerConfig.EnumPoker[]>((pre, v) => {
                        return pre.concat(v.pokers[0].getPoker())
                    }, []).concat(array.pokers[0].getPoker())

                    if (PokerConfig.pokerIsChain(currentPokerEnums)) {
                        current.push(array)
                    }
                }
                return current;
            };

            const findSplicePairs = (composeArray: PokerArray[], target: PokerArray[][]) => {
                if (composeArray.length <= 1) {
                    return target;
                }
                const start = composeArray.shift();
                if (!start) {
                    return target;
                };
                const result = splicePairs(start, composeArray);
                if (result.length > 1) {
                    target.push(result);
                    composeArray = composeArray.filter((v) => {
                        return result.indexOf(v) < 0;
                    })
                }

                return findSplicePairs(composeArray, target);
            }

            // 是否存在两条链子 组成的组合链子
            findSplicePairs([...composePairsArray], []).forEach(v => {
                this.pairsChainPoker.push(new MiniCompose(v, undefined, undefined))
            })

        }

        // 炸弹
        const composeBoomArray = arraies.filter(v => {
            return v.length() === 4 && PokerConfig.pokerIsPairs(v.pokers.map(a => a.getPoker()))
        })

        if (composeBoomArray.length > 1) {
            // 存在顺序 2222 3333 4444
            const spliceBoom = (start: PokerArray, composeArray: PokerArray[]) => {
                const current = [start];
                for (const array of composeArray) {
                    const currentPokerEnums = current.reduce<PokerConfig.EnumPoker[]>((pre, v) => {
                        return pre.concat(v.pokers[0].getPoker())
                    }, []).concat(array.pokers[0].getPoker())

                    if (PokerConfig.pokerIsChain(currentPokerEnums)) {
                        current.push(array)
                    }
                }
                return current;
            };

            const findSpliceBoom = (composeArray: PokerArray[], target: PokerArray[][]) => {
                if (composeArray.length <= 1) {
                    return target;
                }
                const start = composeArray.shift();
                if (!start) {
                    return target;
                };
                const result = spliceBoom(start, composeArray);
                if (result.length > 1) {
                    target.push(result);
                    composeArray = composeArray.filter((v) => {
                        return result.indexOf(v) < 0;
                    })
                }

                return findSpliceBoom(composeArray, target);
            }

            // 是否存在两条链子 组成的组合链子
            findSpliceBoom([...composeBoomArray], []).forEach(v => {
                this.boomChainPoker.push(new MiniCompose(v, undefined, undefined))
            })
        }
    }

    length() {
        return this.arraies.length
    }

    toString() {
        return `
        \n原始:${this.arraies.map(v => v.toString()).join(' ')}
        \n同颜色:${this.sameColorPoker.map(v => v.toString()).join(' ')}
        \n同花色:${this.sameTypePoker.map(v => v.toString()).join(' ')}
        \n组合链:${this.spliceChainPoker.map(v => v.toString()).join(' ')}
        \n相同链:${this.sameChainPoker.map(v => v.toString()).join(' ')}
        \n对子链:${this.pairsChainPoker.map(v => v.toString()).join(' ')}
        \n炸弹链:${this.boomChainPoker.map(v => v.toString()).join(' ')}
        `
    }
}